//
//  uiNode.cpp
//  smu_test1
//
//  Created by jiayi on 16/9/26.
//
//

#include "uiCommon.hpp"
#include "uiNode.h"
#include "uiNodeLine.h"

#define default_width 15   // distance from left ui
#define default_height 5  // distance from top ui

uiNode::~uiNode()
{
    smuDelete( _nodeData );
    smuDelete( _clickChecker );
    _relyFrom.clear();
    _relyTo.clear();
}

bool uiNode::init()
{
    _nodeData = nullptr;
    _moving = false;
    _dirty = true;
    _fake = false;
    _label = nullptr;
    _bg = nullptr;
    _line = nullptr;
    
    _clickChecker = new uiDoubleClickChecker();
    
    if( !_line && !_fake ){
        _line = uiNodeLine::create();
        _line->setRoot( this );
        this->addChild( _line );
    }
    
    if( !_bg ){
        _bg = ui::Scale9Sprite::create( "frame.png" );
        this->addChild( _bg );
    }
    
    // set name
    if( !_label ){
        _label = cocos2d::Label::create();
        _label->setSystemFontSize( g_font_size );
        _label->setSystemFontName( g_font_family );
        _label->setColor( g_grey );
        
        this->addChild( _label );
    }
    
    return Widget::init();
}

void uiNode::setNodeData(smuNode *data)
{
    _nodeData = data;
    
    _label->setString( _nodeData->name );
    Size size( _nodeData->name.length() * _label->getSystemFontSize(), _label->getSystemFontSize() );
    _bg->setContentSize( size );
    _label->setContentSize( size );
    this->setContentSize( size );
    
    _bg->setPosition( Vec2( size.width / 2, size.height / 2 ) );
    _label->setPosition( Vec2( size.width / 2, size.height / 2 ) );
}

void uiNode::bind( cocos2d::Node* layer )
{
    // if already bind
    if( getParent() ){
        return;
    }
    setTouchEnabled( true );
    this->addTouchEventListener( CC_CALLBACK_2( uiNode::eventProcessor, this ) );
    layer->addChild( this );
}

void uiNode::eventProcessor(Ref*, Widget::TouchEventType type)
{
    if( type == TouchEventType::BEGAN ){
        _moving = true;
        _startOffset = getTouchBeganPosition() - getPosition();
    }else if( type == TouchEventType::ENDED || type == TouchEventType::CANCELED ){
        _moving = false;
        _clickChecker->setTime();
        if( _clickChecker->isDoubleClick() ){
            uiNodeManager::getInstance().deleteOrRestoreNode( getNodeData(), !getNodeData()->isDeleted() );
        }
    }else if( type == TouchEventType::MOVED ){
        this->updateReliesPosition();
    }
}

void uiNode::updateData( int type )
{
    switch( type ){
        case EUpdate::Initialize:
        {
            _updateVirtualSize();
            updatePosition();
        }
            break;
            
        case EUpdate::Status:
        {
            _line->updateLine();
            if( getNodeData()->isAvailable() ){
                _label->runAction( TintTo::create( g_color_tint_time, g_grey.r, g_grey.g, g_grey.b ) );
                
            }else{
                _label->runAction( TintTo::create( g_color_tint_time, g_dark_red.r, g_dark_red.g, g_dark_red.b ) );
            }
        }
            break;
            
        case EUpdate::Position:
            updatePosition();
            break;
            
        default:
            break;
    }
}

void uiNode::addFromAndRely( uiNode* node )
{
    _relyFrom.push_back( node );
    node->_relyTo.push_back( this );
}

void uiNode::updatePosition()
{
    if( !_dirty ){
        _line->updateLine();
        return;
    }
    setDirty( false );
    
    if( _nodeData->relyFrom.empty() ){
        setPosition( Vec2( 0, 0 ) );
        return;
    }
    
    uiNode* maxNode = nullptr;
    int maxIndex = -1;
    
    // caculate position depends on left ones (relyFrom)
    for( int i = 0 ; i < _relyFrom.size(); ++ i ){
        uiNode* rely = _relyFrom[i];
        rely->updatePosition();
        maxNode = rely;
    }
    if( maxNode ){
        const Size& maxSize = maxNode->getVirtualSize();
        
        float deltaY = 0;
        for( int i = 0 ; i < maxNode->_relyTo.size(); ++ i ){
            deltaY += maxNode->_relyTo[i]->getVirtualSize().height;
            if( i > 0 ){
                deltaY += default_height;
            }
            if( maxNode->_relyTo[i] == this ){
                maxIndex = i;
                break;
            }
        }
        deltaY -= default_height;
        deltaY = maxSize.height / 2 - deltaY + getVirtualSize().height / 2;
        if( maxIndex != -1 ){
            float x = maxNode->getPositionX() + maxSize.width / 2 + default_width + _label->getContentSize().width / 2;
            float y = maxNode->getPositionY() + deltaY;
            
            Vec2 offset(0,0);
            if( _moving ){
                _offset = getTouchMovePosition() - Vec2( x, y ) - _startOffset;
                this->setPosition( Vec2( x, y ) + _offset );
            }else{
                if( !getNodeData()->isAvailable() ) // cannot move
                {
                    _offset = getPosition() - ( Vec2( x, y ) + _offset );
                }else{
                    this->setPosition( Vec2( x, y ) + _offset );
                }
            }
            _line->updateLine();
        }
    }
}

void uiNode::updateReliesPosition()
{
    setDirty( true );
    updatePosition();
    for( int i = 0 ; i < _relyTo.size(); ++ i ){
        _relyTo[i]->setDirty( true );
        _relyTo[i]->updateReliesPosition();
    }
}

void uiNode::_updateVirtualSize()
{
    float totalHeight = 0;
    for( int i = 0 ; i < _relyTo.size(); ++ i ){
        _relyTo[i]->_updateVirtualSize();
        totalHeight += _relyTo[i]->getVirtualSize().height;
    }
    
    if( totalHeight > 0 ){
        totalHeight += ( _relyTo.size() - 1 ) * default_height;
    }
    
    Size s( _label->getContentSize().width, max( _label->getContentSize().height, totalHeight ) );
    if( _virualSize.width != s.width || _virualSize.height != s.height ){
        _virualSize = s;
        // need to update position
        setDirty( true );
    }
}

const cocos2d::Size& uiNode::getVirtualSize() const
{
    return _virualSize;
}
